<?php

namespace common\service;


use common\exception\LogicException;
use common\model\EntityModel;
use common\model\MotionCaptureDataModel;
use common\model\MotionCaptureDataRelationModel;
use common\model\TaskModel;
use common\model\UserModel;
use common\model\VersionModel;
use support\ErrorCode;
use support\SingletonTrait;

class MotionCaptureDataService
{

    use SingletonTrait;

    /**
     * 保存动捕数据
     * @param $data
     * @param $userId
     * @return array
     * @throws \Throwable
     */
    public function saveMotionCaptureData($data, $userId)
    {
        //1.添加动捕数据
        //2.添加动捕关联数据
        $motionCaptureData = $data['motion_capture_data'];
        $motionCaptureDataRelation = $data['motion_capture_data_relation'];
        $motionCaptureDataModel = model(MotionCaptureDataModel::class);
        $res = [];
        if (empty($motionCaptureData['id'])) {
            //如有相同的不能在创建
            $motionCapture = model(MotionCaptureDataModel::class)->where([
                'task_id' => $motionCaptureData['task_id'],
                'name' => $motionCaptureData['name']
            ])->field("id")->find();

            if (!empty($motionCapture)) {
                throw new LogicException("the same motion capture data already exists", ErrorCode::THE_SAME_MOTION_CAPTURE_DATA_ALREADY_EXISTS);
            }

            //事务处理
            $motionCaptureDataModel->startTrans();
            try {
                $res = $this->createMotionCaptureData($motionCaptureData, $motionCaptureDataRelation);
                $motionCaptureDataModel->commit();
            } catch (\Throwable $e) {
                $motionCaptureDataModel->rollback();
                throw $e;
            }
        } else {
            //查出原来的 与之对比
            $motionCaptureDataRelationList = model(MotionCaptureDataRelationModel::class)->where([
                'motion_capture_data_id' => $motionCaptureData['id']
            ])->select();

            // 比对出 新增, 修改, 删除的
            // 新增 与删除是对比资产

            // 修改 是对比出相同的资产上是否不同的文件和演员
            $oldRelationMap = array_column($motionCaptureDataRelationList, null, "entity_id");
            $newRelationMap = array_column($motionCaptureDataRelation, null, "entity_id");

            //新增的
            $needAddRelation = array_diff_key($newRelationMap, $oldRelationMap);

            //删除的id
            $needDeleteRelation = array_diff_key($oldRelationMap, $newRelationMap);
            $needDeleteRelationId = array_column($needDeleteRelation, 'id');
            //需要修改的
            $updateRelationData = [];
            foreach ($oldRelationMap as $oldRelationMapIndex => $oldRelationMapItem) {
                // 如果存在, 且 演员和 文件不相同
                if (isset($newRelationMap[$oldRelationMapIndex])) {
                    $newRelationMapItem = $newRelationMap[$oldRelationMapIndex];
                    $oldRelationStr = join("_", [$oldRelationMapItem["actor"], $oldRelationMapItem["file"], $oldRelationMapItem["type"]]);
                    $newRelationStr = join("_", [$newRelationMapItem["actor"], $newRelationMapItem["file"], $newRelationMapItem["type"]]);
                    if ($oldRelationStr != $newRelationStr) {
                        $updateRelationData[] = [
                            'id' => $oldRelationMapItem['id'],
                            'actor' => $newRelationMapItem['actor'],
                            'file' => $newRelationMapItem['file'],
                            'type' => $newRelationMapItem['type'],
                            'updated_by' => $userId,
                            'updated' => time()
                        ];
                    }
                }
            }

            //添加数据处理
            $needAddRelationResult = [];
            foreach ($needAddRelation as $needAddRelationItem) {
                $needAddRelationItem['motion_capture_data_id'] = $motionCaptureData['id'];
                $needAddRelationItem['created_by'] = $userId;
                $needAddRelationItem['updated_by'] = $userId;
                $needAddRelationItem['created'] = time();
                $needAddRelationItem['updated'] = time();
                $needAddRelationResult[] = $needAddRelationItem;
            }

            $motionCaptureDataModel->startTrans();
            try {
                //更新动捕数据
                $res['motion_capture_data'] = model(MotionCaptureDataModel::class)->modifyItem($motionCaptureData);
                //关联新增
                if (!empty($needAddRelationResult)) {
                    $res['add_relation_list'] = model(MotionCaptureDataRelationModel::class)->addAll($needAddRelationResult);
                }

                //关联删除
                if (!empty($needDeleteRelationId)) {
                    $res['delete_relation_list'] = model(MotionCaptureDataRelationModel::class)->where(['id' => ["IN", $needDeleteRelationId]])->delete();
                }
                //关联修改
                if (!empty($updateRelationData)) {
                    model(MotionCaptureDataRelationModel::class)->saveAll($updateRelationData);
                }
                $motionCaptureDataModel->commit();
            } catch (\Throwable $e) {
                $motionCaptureDataModel->rollback();
                throw $e;
            }
        }

        return $res;

    }

    /**
     * 处理动捕数据中关联的资产
     * @param $taskId
     * @param $motionCaptureDataId
     * @throws \think\Exception
     */
    public function dealMotionCaptureDataRelationEntity($taskId, $motionCaptureDataId)
    {
        // 通过版本找出 sequence
        $task = model(TaskModel::class)->find($taskId);
        $entity = model(EntityModel::class)->field("id,JSON_UNQUOTE(JSON_EXTRACT(json,'$.sequence_asset')) as sequence_asset")->find($task['entity_id']);
        // 处理 动捕数据的关联 只用于更改 entity json 中 sequence_asset
        // 需要查询出所有关联数据的资产,然后在进行 sequence_asset覆盖
        if (!empty($entity)) {
            $motionCaptureDataList = model(MotionCaptureDataModel::class)
                ->join("motion_capture_data_relation on motion_capture_data_relation.motion_capture_data_id = motion_capture_data.id")
                ->where(['motion_capture_data.id' => ["IN", $motionCaptureDataId]])
                ->field("motion_capture_data_relation.entity_id")
                ->group("motion_capture_data_relation.entity_id")
                ->select();
            $motionCaptureDataEntityIds = array_column($motionCaptureDataList, "entity_id");

            $entitySequenceAsset = [];
            if (!empty($entity['sequence_asset'])) {
                $entitySequenceAsset = explode(",", $entity['sequence_asset']);
            }
            //更新json中的值
            if (!empty(array_diff($motionCaptureDataEntityIds, $entitySequenceAsset)) || !empty(array_diff($entitySequenceAsset, $motionCaptureDataEntityIds))) {
                $commonService = CommonService::instance('entity');
                $entityUpdateData = [
                    'id' => $entity['id'],
                    'sequence_asset' => join(",", $motionCaptureDataEntityIds),
                ];
                $commonService->update($entityUpdateData, 'sequence', false);
            }
        }
    }

    /**
     * 获取动捕数据列表
     * @param $param
     * @return array
     * @throws \think\Exception
     */
    public function getMotionCaptureDataList($param)
    {
        $filter = $param['filter'];
        $page = $param['page'] ?? [1, C('default_page_total')];
        $fields = $param['fields'] ?? "id,task_id,name,remark";
        $motionCaptureDataList = model(MotionCaptureDataModel::class)->where($filter)->page(...$page)->field($fields)->select();

        if (empty($motionCaptureDataList)) {
            return [];
        }

        $motionCaptureDataIds = [];
        $motionCaptureDataTaskId = $motionCaptureDataList[0]['task_id'];
        foreach ($motionCaptureDataList as $motionCaptureDataItem) {
            $motionCaptureDataIds[] = $motionCaptureDataItem["id"];
        }

        $versionList = model(VersionModel::class)
            ->where(['link_id' => $motionCaptureDataTaskId, 'module_id' => module_by_code('task')['id']])
            ->field("id,number,JSON_UNQUOTE(JSON_EXTRACT(json, '$.version_motion_capture_data')) as motion_capture_data_id")
            ->select();

        $versionMotionCaptureDataMap = [];

        if (!empty($versionList)) {
            //按照版本号来排序
            multiple_sort_by($versionList, ['number' => 'asc']);
            foreach ($versionList as $versionItem) {
                if (!empty($versionItem['motion_capture_data_id'])) {
                    $currentMotionCaptureDataIds = explode(",", $versionItem['motion_capture_data_id']);
                    unset($versionItem['motion_capture_data_id']);
                    foreach ($currentMotionCaptureDataIds as $currentMotionCaptureDataId) {
                        $versionMotionCaptureDataMap[$currentMotionCaptureDataId] = $versionItem;
                    }
                }
            }
        }

        $motionCaptureDataRelationList = model(MotionCaptureDataRelationModel::class)
            ->where(['motion_capture_data_id' => ["IN", $motionCaptureDataIds]])
            ->field("id,motion_capture_data_id,entity_id,actor,file,type")
            ->select();

        $entityIds = [];
        $actor = [];
        foreach ($motionCaptureDataRelationList as $motionCaptureDataRelationItem) {
            $entityIds[$motionCaptureDataRelationItem['entity_id']] = $motionCaptureDataRelationItem['entity_id'];
            if (!empty($motionCaptureDataRelationItem['actor'])) {
                $actor[$motionCaptureDataRelationItem['actor']] = $motionCaptureDataRelationItem['actor'];
            }
        }

        $entityList = [];
        if (!empty($entityIds)) {
            $entityList = model(EntityModel::class)->where(['id' => ["IN", $entityIds]])->field("id,name,code,JSON_UNQUOTE(JSON_EXTRACT(entity.json, '$.asset_perform_species')) AS asset_perform_species")->select();
            $entityList = array_column($entityList, null, 'id');
        }


        $userList = [];
        if (!empty($actor)) {
            $userList = model(UserModel::class)->where(['id' => ["IN", $actor]])->field("id,name,avatar")->select();
            $userList = array_column($userList, null, 'id');
        }

        $motionCaptureDataRelationGroup = [];
        foreach ($motionCaptureDataRelationList as $motionCaptureDataRelationIndex => $motionCaptureDataRelationItem) {
            $motionCaptureDataRelationItem['actor'] = $userList[$motionCaptureDataRelationItem['actor']] ?? null;
            $motionCaptureDataRelationItem['entity'] = $entityList[$motionCaptureDataRelationItem['entity_id']] ?? null;
            $motionCaptureDataRelationList[$motionCaptureDataRelationIndex] = $motionCaptureDataRelationItem;
            $motionCaptureDataRelationGroup[$motionCaptureDataRelationItem['motion_capture_data_id']][] = $motionCaptureDataRelationItem;
        }

        return array_map(function ($motionCaptureDataItem) use ($motionCaptureDataRelationGroup, $versionMotionCaptureDataMap) {
            $motionCaptureDataItem['latest_version'] = $versionMotionCaptureDataMap[$motionCaptureDataItem['id']] ?? null;
            $motionCaptureDataItem['relation_list'] = $motionCaptureDataRelationGroup[$motionCaptureDataItem['id']] ?? [];
            return $motionCaptureDataItem;
        }, $motionCaptureDataList);
    }

    /**
     * 移除动捕数据
     * @param $filter
     * @return array
     * @throws \Throwable
     */
    public function removeMotionCaptureData($filter)
    {
        $motionCaptureDataModel = model(MotionCaptureDataModel::class);
        $motionCaptureDataList = $motionCaptureDataModel->where($filter)->select();
        $result = [];
        if (empty($motionCaptureDataList)) {
            return $result;
        }

        $motionCaptureDataIds = array_column($motionCaptureDataList, 'id');
        $motionCaptureDataRelationList = model(MotionCaptureDataRelationModel::class)->where(['motion_capture_data_id' => ["IN", $motionCaptureDataIds]])->select();
        $motionCaptureDataRelationIds = array_column($motionCaptureDataRelationList, 'id');

        $motionCaptureDataModel->startTrans();
        try {
            $result['motion_capture_data'] = $motionCaptureDataModel->where(["id" => ["IN", $motionCaptureDataIds]])->delete();
            $result['motion_capture_data_relation'] = model(MotionCaptureDataRelationModel::class)->where(["id" => ["IN", $motionCaptureDataRelationIds]])->delete();
            $motionCaptureDataModel->commit();
            return $result;
        } catch (\Throwable $e) {
            $motionCaptureDataModel->rollback();
            throw $e;
        }
    }

    /**
     * 发布动捕任务
     * @param $data
     * @return array
     * @throws \Throwable
     * @throws \think\Exception
     */
    public function publishMotionCaptureTask($data)
    {
        //拿取该任务所有的动捕数据
        $motionCaptureDataIds = model(MotionCaptureDataModel::class)->where(['task_id' => $data['version']['link_id']])->column('id');

        if (empty($motionCaptureDataIds)) {
            throw new LogicException('motion capture data not exist', ErrorCode::MOTION_CAPTURE_DATA_NOT_EXIST);
        }

        //1.发布完了之后 ,
        //2.需要同步 动捕数据 ,
        //3.以及更新关联的 资产以及关卡
        $data['version']['module_id'] = module_by_code("task")['id'];
        $data['version']['version_motion_capture_data'] = join(",", $motionCaptureDataIds);
        $res = VersionService::getInstance()->create($data);
        //版本id
        $taskId = $res['version']['link_id'];
        //更新关联的资产与关卡
        $this->dealMotionCaptureDataRelationEntity($taskId, $res['version']['version_motion_capture_data']);
        return $res;

    }

    /**
     * 创建动捕数据
     * @param $motionCaptureData
     * @param $motionCaptureDataRelation
     * @return array
     * @throws \Exception
     */
    public function createMotionCaptureData($motionCaptureData, $motionCaptureDataRelation)
    {
        $motionCaptureData = model(MotionCaptureDataModel::class)->addItem($motionCaptureData);
        foreach ($motionCaptureDataRelation as $motionCaptureDataRelationIndex => $motionCaptureDataRelationItem) {
            $motionCaptureDataRelationItem['motion_capture_data_id'] = $motionCaptureData['id'];
            $motionCaptureDataRelationItem['created'] = $motionCaptureData['created'];
            $motionCaptureDataRelationItem['created_by'] = $motionCaptureData['created_by'];
            $motionCaptureDataRelationItem['updated'] = $motionCaptureData['created'];
            $motionCaptureDataRelationItem['updated_by'] = $motionCaptureData['created_by'];
            $motionCaptureDataRelation[$motionCaptureDataRelationIndex] = $motionCaptureDataRelationItem;
        }
        $motionCaptureDataRelation = model(MotionCaptureDataRelationModel::class)->addAll($motionCaptureDataRelation);
        return ['motion_capture_data' => $motionCaptureData, 'motion_capture_data_relation' => $motionCaptureDataRelation];
    }
}
